package cmpe451.group7.ourcity.dao.impl;

import java.io.Serializable;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import cmpe451.group7.ourcity.dao.UserDAO;
import cmpe451.group7.ourcity.entity.Comment;
import cmpe451.group7.ourcity.entity.Place;
import cmpe451.group7.ourcity.entity.User;
import cmpe451.group7.ourcity.util.PasswordHash;

@Repository("userDAO")
public class UserDAOImpl extends GenericDAOImpl<User> implements UserDAO,
		Serializable {

	private static final long serialVersionUID = 1L;

	public UserDAOImpl() {
		super();
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public List<User> findAll() {
		return super.findAll(User.class);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public User findByID(long id) {
		return super.findByID(User.class, id);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public User insertNewUser(String name, String surname, String email,
			String password) throws NoSuchAlgorithmException,
			InvalidKeySpecException {
		Session session = this.getCurrentSession();
		User user = new User();

		// Set<Badge> badge = new HashSet<Badge>();
		// badge.add(newbiesBadge);
		// user.setBadges(badge);

		user.setName(name);
		user.setSurname(surname);
		user.setEmail(email);

		// hash the user's password before storing it to the database
		password = PasswordHash.createHash(password);
		user.setPassword(password);

		session.save(user);
		//session.flush();

		return user;
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public User findUserByEmail(String email) {
		Session session = this.getCurrentSession();

		Criteria criteria = session.createCriteria(User.class);
		criteria.add(Restrictions.like("email", email));

		@SuppressWarnings("unchecked")
		List<User> users = criteria.setResultTransformer(
				Criteria.DISTINCT_ROOT_ENTITY).list();

		if (users == null || users.isEmpty()) {
			return null;
		} else {
			return users.get(0);
		}
	}

	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public User updateUserInfo(String userInfo, Long userID) {
		Session session = this.getCurrentSession();

		User user = (User) session.get(User.class, userID);
		if (user == null) {
			return null;
		}

		user.setUserInfo(userInfo);

		session.update(user);
		//session.flush();

		return user;
	}

	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public User updateAboutMe(String aboutMe, Long userID) {
		Session session = this.getCurrentSession();
		User user = (User) session.get(User.class, userID);

		if (user == null)
			return null;

		user.setAboutMe(aboutMe);

		session.update(user);
		//session.flush();

		return user;
	}

	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public List<Comment> getCommentsofUser(User user) {
		Session session = this.getCurrentSession();

		String hql = "select a from Comment a " + "where "
				+ "user_userID like :pn " + "group by a ";

		Query query = session.createQuery(hql);
		query.setParameter("pn", user.getUserID());

		List<Comment> comments = query.list();

		return comments;
	}

	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public boolean likePlace(Place place, User user) {
		boolean placeAdded = false;

		Session session = this.getCurrentSession();

		Set<Place> likedPlace = user.getLikedPlace();
		if (likedPlace != null && !likedPlace.contains(place)) {
			likedPlace.add(place);
			placeAdded = true;
			session.update(user);
			//session.flush();
		}

		return placeAdded;
	}

	public List<Place> getLikedPlace(User user) {

		Set<Place> likedPlaces = new HashSet<Place>();
		likedPlaces = user.getLikedPlace();

		List<Place> likedPlacesList = new ArrayList<Place>();
		if (likedPlaces.size() != 0) {
			likedPlacesList.addAll(likedPlaces);
		} else {
			likedPlacesList = null;
		}
		return likedPlacesList;

	}

}
